<?php

namespace mybackend\controllers;

use common\repositories\myhtsq\ContractManageRepository;
use Yii;
use common\error\ErrorCode;
use common\services\myhtsq\ContractService;
use common\services\myhtsq\ContractReceivableService;
use common\services\myhtsq\InvoiceService;
use common\services\myhtsq\ContractPaymentService;
use common\models\myhtsq\ContractReceivableModel;
use common\models\myhtsq\InvoiceModel;
use common\models\myhtsq\ContractPaymentModel;
use common\entities\myhtsq\ActionCode;
use common\entities\ConfigEntity;
use yii\filters\AccessControl;

/**
 * Description of ReceivableController
 * 应收款控制器
 * @author chenxc
 */
class ReceivableController extends BaseController
{

    private $_contractService;
    private $_contractReceivableService;
    private $_invoiceService;
    private $_contractPaymentService;

    public function __construct($id, $module, ContractService $contractService, ContractReceivableService $contractReceivableService, InvoiceService $invoiceService, ContractPaymentService $contractPaymentService, $config = array())
    {
        $this->_contractService = $contractService;
        $this->_contractReceivableService = $contractReceivableService;
        $this->_invoiceService = $invoiceService;
        $this->_contractPaymentService = $contractPaymentService;
        parent::__construct($id, $module, $config);
    }

    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['receivable-expired-remind'],
                        'allow' => true,
                    ],
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ]
        ];
    }

    protected function roleAuthRules()
    {
        return [
            'actions' => ['ChangeReceivableDate', 'ChangeResponsiblePerson', 'DeleteContractPayment', 'DeleteContractReceivable',
                'DeleteInvoice', 'GetCanUseInvoiceInfo', 'GetContractPaymentHaveAmountByContract', 'GetContractReceivable',
                'GetContractUnifiedInfo', 'GetInvoiceReceivableInfoByContract', 'GetParentInvoiceInfo', 'MarkBadDebt',
                'MarkOperation', 'SaveContractPayment', 'SaveContractReceivable', 'SaveInvoiceReceivable', 'SplitContractReceivalble'],
            'rules' => [
                [
                    'allow' => true,
                    'actionCodeMaps' => [
                        'ChangeReceivableDate' => ActionCode::CONTRACT_MNG,
                        'ChangeResponsiblePerson' => ActionCode::CONTRACT_MNG,
                        'DeleteContractPayment' => ActionCode::CONTRACT_MNG,
                        'DeleteContractReceivable' => ActionCode::CONTRACT_MNG,
                        'DeleteInvoice' => ActionCode::INVOICE_MNG,
                        'GetCanUseInvoiceInfo' => ActionCode::INVOICE_MNG,
                        'GetContractPaymentHaveAmountByContract' => ActionCode::CONTRACT_VIEW,
                        'GetContractReceivable' => ActionCode::CONTRACT_VIEW,
                        'GetContractUnifiedInfo' => ActionCode::CONTRACT_VIEW,
                        'GetInvoiceReceivableInfoByContract' => ActionCode::INVOICE_VIEW,
                        'GetParentInvoiceInfo' => ActionCode::INVOICE_VIEW,
                        'MarkBadDebt' => ActionCode::CONTRACT_MNG,
                        'MarkOperation' => ActionCode::CONTRACT_MNG,
                        'SaveContractPayment' => ActionCode::CONTRACT_MNG,
                        'SaveContractReceivable' => ActionCode::CONTRACT_MNG,
                        'SaveInvoiceReceivable' => ActionCode::INVOICE_MNG,
                        'SplitContractReceivalble' => ActionCode::CONTRACT_MNG,
                    ],
                ],
                [
                    'allow' => true,
                    'actionCodeMaps' => [
                        'DeleteContractPayment' => ActionCode::CONTRACT_PAYMENT_DELETE,
                        'SaveContractPayment' => ActionCode::CONTRACT_PAYMENT_SAVE,

                    ],
                ]
            ]
        ];
    }

    /**
     * 获取合同的统一信息
     */
    public function actionGetContractUnifiedInfo()
    {
        $signAmount = $rentAmount = $deliveryAmount = $billingAmount = $paymentAmount = $income_amount = 0;
        $contractId = $this->getParam('contractId');
        // 合同信息
        $contract = $this->_contractService->getContractInfo($contractId);
        if (isset($contract) && isset($contract['contract'])) {
            $signAmount = $contract['contract']['sign_amount'];
            $rentAmount = $contract['contract']['rent_amount'];
            $deliveryAmount = $contract['contract']['delivery_amount'];
            $income_amount = $contract['contract']['income_amount'];
        }
        // 应收款项信息
        $receivables = $this->_contractReceivableService->getReceivableInfoByContractId($contractId);
        if (isset($receivables) && count($receivables) > 0) {
            foreach ($receivables as $k => $v) {
                $billingAmount += floatval($v['billing_amount']);
                $paymentAmount += floatval($v['received_amount']);
            }
        }
        // 发票信息
        $invoices = $this->_invoiceService->getInvoiceListByContractId($contractId);
        $invoices = $this->setInvoiceReceivable($invoices, $receivables);
        // 回款信息
        $payments = $this->_contractPaymentService->getPaymentInfoByContractId($contractId);

        //回款金额中供应商线下活动特殊处理
        if($contract['contract']['business_type_id'] == 'f854fa59-54ca-11e7-9f96-000c29310f8b' ||
            $contract['contract']['business_type_id'] == '9a96f3dc-54ca-11e7-9f96-000c29310f8b' ||
            $contract['contract']['business_type_id'] == 'f851bc86-54ca-11e7-9f96-000c29310f8b'
            ) {
            $paymentAmount = 0;
            foreach ($payments as $item) {
                $paymentAmount += floatval($item['payment_amount']);
            }
        }

        // 收入信息
        //$received = ContractSuppliersPaymentRepository::getPaymentListByContractid($contractId);

        $summary = array(
            'signAmount' => $signAmount,
            'rentAmount' => $rentAmount,
            'deliveryAmount' => $deliveryAmount,
            'billingAmount' => $billingAmount,
            'paymentAmount' => $paymentAmount,
            'incomeAmount' => $income_amount
        );

        $result = array(
            'summary' => $summary,
            'receivables' => $receivables,
            'invoices' => $invoices,
            'payments' => $payments,
            //'received' => $received
        );

        $this->exportJson($result);
    }

    private function setInvoiceReceivable($invoices, $receivables)
    {
        if (!empty($invoices) && !empty($receivables)) {
            $result = [];
            foreach ($invoices as $invoice) {
                $invoice_id = $invoice['invoice_id'];
                $invoiceReceivables = $this->_invoiceService->getInvoiceReceivable($invoice_id);
                $invoice_receivable = '';
                if (!empty($invoiceReceivables)) {
                    $invoice_receivables = [];
                    foreach ($invoiceReceivables as $invoiceReceivable) {
                        $receivable_id = $invoiceReceivable['receivable_id'];
                        foreach ($receivables as $key => $receivable) {
                            if ($receivable_id == $receivable['receivable_id'] && !array_key_exists($receivable_id, $invoice_receivables)) {
                                $invoice_receivables[$receivable_id] = $key + 1;
                                break;
                            }
                        }
                    }
                    if (!empty($invoice_receivables)) {
                        $invoice_receivable = implode(',', $invoice_receivables);
                    }
                }

                $invoice['invoice_receivable'] = $invoice_receivable;
                $result[] = $invoice;
            }

            return $result;
        }

        return $invoices;
    }

    /**
     * 根据合同ID获取对应的应收款信息
     */
    public function actionGetContractReceivable()
    {
        $contractId = $this->getParam('contractId');
        $receivables = $this->_contractReceivableService->getReceivableInfoByContractId($contractId, false);
        $this->exportJson($receivables, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 保存合同应收款项信息
     */
    public function actionSaveContractReceivable()
    {
        $this->exitIfNotPost();
        $contractReceivableModel = new ContractReceivableModel(['scenario' => 'savecontractreceivable']);
        if ($contractReceivableModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractReceivableService->saveContractReceivable($contractReceivableModel);
            $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 删除合同应收款信息
     */
    public function actionDeleteContractReceivable()
    {
        $receivableId = $this->getParam('receivable_id', 'post');
        $result = $this->_contractReceivableService->deleteContractReceivable($receivableId);
        $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 保存合同应收款拆分信息
     */
    public function actionSplitContractReceivalble()
    {
        $this->exitIfNotPost();
        $contractReceivableModel = new ContractReceivableModel(['scenario' => 'splitontractreceivable']);
        if ($contractReceivableModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractReceivableService->splitContractReceivable($contractReceivableModel);
            $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 保存合同应收款项责任人变更信息
     */
    public function actionChangeResponsiblePerson()
    {
        $this->exitIfNotPost();
        $contractReceivableModel = new ContractReceivableModel(['scenario' => 'changeresponsibleperson']);
        if ($contractReceivableModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractReceivableService->changeResponsiblePerson($contractReceivableModel);
            $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 保存合同应收款项应收款项变更信息
     */
    public function actionChangeReceivableDate()
    {
        $this->exitIfNotPost();
        $contractReceivableModel = new ContractReceivableModel(['scenario' => 'changeresponsibleperson']);
        if ($contractReceivableModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractReceivableService->changeReceivableDate($contractReceivableModel);
            $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 标记为坏账
     */
    public function actionMarkBadDebt()
    {
        $receivableId = $this->getParam('receivable_id', 'post');
        $isBadDebt = $this->getParam('is_bad_debt', 'post');
        $result = $this->_contractReceivableService->markBadDebt($receivableId, $isBadDebt);
        $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 标记为运营关注
     */
    public function actionMarkOperation()
    {
        $receivableId = $this->getParam('receivable_id', 'post');
        $isOperation = $this->getParam('is_operation', 'post');
        $result = $this->_contractReceivableService->markOperation($receivableId, $isOperation);
        $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 保存发票信息（与应收款的关系）
     */
    public function actionSaveInvoiceReceivable()
    {
        $this->exitIfNotPost();
        $invoiceModel = new InvoiceModel(['scenario' => 'saveinvoice']);
        if ($invoiceModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractReceivableService->saveInvoiceReceivable($invoiceModel);
            $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     *  获取可以作为父级发票的发票信息
     */
    public function actionGetParentInvoiceInfo()
    {
        $keyword = $this->getParam('keyword');
        $result = $this->_invoiceService->getParentInvoiceInfo($keyword);
        $this->exportJson($result);
    }

    /**
     * 获取未关联的发票
     */
    public function actionGetCanUseInvoiceInfo()
    {
        $contractId = $this->getParam('contractId');
        $keyword = $this->getParam('keyword');
        $result = $this->_invoiceService->getCanUseInvoiceInfo($contractId, $keyword);
        $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 删除发票信息
     */
    public function actionDeleteInvoice()
    {
        $invoiceId = $this->getParam('invoice_id', 'post');
        $result = $this->_invoiceService->deleteInvoice($invoiceId, true);
        $this->exportJson($result, $this->_invoiceService->getErrCode(), $this->_invoiceService->getErrMsg());
    }

    /**
     * 根据合同id获取对应的 发票与应收款对应关系 记录
     */
    public function actionGetInvoiceReceivableInfoByContract()
    {
        $contractId = $this->getParam('contractId');
        $result = $this->_contractReceivableService->getInvoiceReceivableInfoByContractId($contractId);
        $this->exportJson($result, $this->_contractReceivableService->getErrCode(), $this->_contractReceivableService->getErrMsg());
    }

    /**
     * 编辑回款（绑定发票）
     */
    public function actionBindContractPaymentToInvoice()
    {
        $this->exitIfNotPost();
        $contractPaymentModel = new ContractPaymentModel(['scenario' => 'savecontractpayment']);
        if ($contractPaymentModel->load(Yii::$app->request->post(), '')) {
            $result = $this->_contractPaymentService->bindContractPaymentToInvoice($contractPaymentModel);
            $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 保存合同回款信息
     */
    public function actionSaveContractPayment()
    {
        $this->exitIfNotPost();
        $contractPaymentModel = new ContractPaymentModel(['scenario' => 'savecontractpayment']);
        if ($contractPaymentModel->load(Yii::$app->request->post(), '')) {
            // 计算支付宝\微信提现手续费和费率
            $model = $contractPaymentModel->attributes;
            $contract = ContractManageRepository::getContractInfoByContractid($contractPaymentModel->contract_id);
            $businesstypeid = $contract['business_type_id'];
            if (isset($model['pay_way']) && !empty($model['pay_way'])) {
                if($businesstypeid == '9a96f3dc-54ca-11e7-9f96-000c29310f8b'){
                    //移动工程协同
                    $withdraw_fee_rate = \Yii::$app->params['withdraw_fee_rate'][$model['pay_way']];
                }else{
                    //云采购的费用费率
                    $withdraw_fee_rate = \Yii::$app->params['withdraw_fee_rate_ycg'][$model['pay_way']];
                }

                $withdraw_fee = round($model['payment_amount'] * $withdraw_fee_rate / 100, 2);

                $contractPaymentModel->withdraw_fee = $withdraw_fee;
                $contractPaymentModel->withdraw_fee_rate = $withdraw_fee_rate;
            }else{
                $contractPaymentModel->withdraw_fee = 0;
                $contractPaymentModel->withdraw_fee_rate = 0;
            }
            unset($model);

            $result = $this->_contractPaymentService->saveContractPayment($contractPaymentModel);

            if ($result) {
                // 更新改合同的回款状态
                $this->_contractPaymentService->updateContractPayinfoStatus($contractPaymentModel->contract_id, 1);

                //如果是釆宝单独处理回款金额[因与发票等无关联,所以需要特殊处理]
                if($businesstypeid == 'f851bc86-54ca-11e7-9f96-000c29310f8b'){
                    $this->_contractPaymentService->refreshBackAmount($contractPaymentModel->contract_id);
                }
            }

            $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
        } else {
            $this->errorParam();
        }
    }

    /**
     * 保存合同回款信息,确认回款调用,多对多
     */
    public function actionSaveContractPaymentByMany()
    {
        $this->exitIfNotPost();
        $postdata = Yii::$app->request->post();
        if(isset($postdata['pname'])){
            $pname = $postdata['pname'];
        }else{
            $pname = '';
        }
        //釆宝只更新状态,移动工程协同需要创建合同回款信息
        if($pname == '云采购采宝'){
            $payinfos = $postdata["qureyData"]['contracts'];
            foreach($payinfos as $payinfo){
                $this->_contractPaymentService->updtaeContractPayInfoStatusById($payinfo['payinfo_id'] ,1);
            };
            $this->exportJson([], '0', '');
        }else{
            $refundInfoLists = $postdata['refundInfoList'];
            $dhkItems = $postdata['dhkItems'];
            $dhkMaxAmount = 0;
            $dhkMaxGuid = '';
            $dhkSumAmount = 0;
            $paySumAmount = 0;
            $payFeeSumAmount = 0;


            $contractPaymentModel = new ContractPaymentModel(['scenario' => 'savecontractpayment']);
            //循环处理每笔回款
            foreach($refundInfoLists as $rlist){
                if ($contractPaymentModel->load($rlist, '')) {
                    $paySumAmount += $rlist['payment_amount'];
                    if (isset($rlist['pay_way']) && !empty($rlist['pay_way'])) {
                        $withdraw_fee_rate = \Yii::$app->params['withdraw_fee_rate'][$rlist['pay_way']];
                        $withdraw_fee = round($rlist['payment_amount'] * $withdraw_fee_rate / 100, 2);
                        $payFeeSumAmount += $withdraw_fee;
                    }
                }
            }
            //接口数据一次处理,多出来的金额再生成一笔待引入回款
            foreach($dhkItems as $dhkitem){
                //找出金额最大的一笔,剩余金额放在上面生成待回款
                $willPayAmount = 0;
                $willPayAmount = $dhkitem['payment_amount'] - $dhkitem['have_payment_amount'];
                if($dhkMaxAmount<$willPayAmount){
                    $dhkMaxAmount = $willPayAmount;
                    $dhkMaxGuid = $dhkitem['DhkGUID'];
                }
                $dhkSumAmount += $willPayAmount;
            }

            $diffAmount = $dhkSumAmount - ($paySumAmount - $payFeeSumAmount);
            if($diffAmount < 0){
                $this->exportJson([], '999', '待回款金额合计不能小于支付金额合计!');
            }

            //校验通过处理数据
            //循环处理每笔回款
            $configDataBase = ConfigEntity::getDb();
            $trans = $configDataBase->beginTransaction();
            foreach($refundInfoLists as $rlist){
                if ($contractPaymentModel->load($rlist, '')) {
                    // 计算支付宝\微信提现手续费和费率
                    $model = $contractPaymentModel->attributes;
                    $paySumAmount += $model['payment_amount'];
                    if (isset($model['pay_way']) && !empty($model['pay_way'])) {
                        $withdraw_fee_rate = \Yii::$app->params['withdraw_fee_rate'][$model['pay_way']];
                        $withdraw_fee = round($model['payment_amount'] * $withdraw_fee_rate / 100, 2);
                        $payFeeSumAmount += $withdraw_fee;

                        $contractPaymentModel->withdraw_fee = $withdraw_fee;
                        $contractPaymentModel->withdraw_fee_rate = $withdraw_fee_rate;
                        $contractPaymentModel->input_date = $nowtime = ConfigEntity::getDbNowDate();
                    }
                    unset($model);

                    $result = $this->_contractPaymentService->saveContractPaymentByMany($contractPaymentModel);

                    if ($result) {
                        // 更新改合同的回款状态
                        $result = $this->_contractPaymentService->updtaeContractPayInfoStatusById($rlist['payinfo_id'] ,1);
                    }

                    if ($result === false) {
                        // 回滚事务
                        $trans->rollBack();
                        return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_FORM_SAVE_ERP_FAIL);
                    }
                } else {
                    $trans->rollBack();
                    $this->errorParam();
                }
            }
            foreach($dhkItems as $dhk){
                if($dhk['DhkGUID']==$dhkMaxGuid && $diffAmount>0){
                    $result = $this->_contractPaymentService->updateAccountHk($dhk['DhkGUID'],$dhk['payment_amount']-$dhk['have_payment_amount']-$diffAmount);
                }else{
                    $result = $this->_contractPaymentService->updateAccountHk($dhk['DhkGUID'],$dhk['payment_amount']-$dhk['have_payment_amount']);
                }
                if ($result === false) {
                    // 回滚事务
                    $trans->rollBack();
                    return self::setAndReturn(ErrorCode::ERR_CONTRACT_PAYMENT_FORM_SAVE_ERP_FAIL);
                }
            }
            $trans->commit();
            $this->exportJson([], 0, '');
        }
    }

    public function actionGetContractPayment()
    {
        $id = $this->getParam('payment_id');
        $result = $this->_contractPaymentService->getPaymentInfoById($id);
        $this->exportJson($result);
    }

    /**
     * 获取发票绑定的回款列表
     */
    public function actionGetPaymentListByInvoiceId()
    {
        $invoiceId = $this->getParam('invoice_id', 'get', '');
        $result = $this->_contractPaymentService->getContractPaymentInfoByInvoiceId($invoiceId);
        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /**
     * 解除回款与发票的关联关系
     */
    public function actionUnBindPaymentForInvoice()
    {
        $paymentIds = $this->getParam('payment_ids', 'post', []);//要取消绑定的paymentId集合
        $result = $this->_contractPaymentService->unBindPaymentForInvoice($paymentIds);
        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /**
     * 删除回款信息
     */
    public function actionDeleteContractPayment()
    {
        $paymentId = $this->getParam('payment_id', 'post');
        $dhkId = $this->getParam('Dhk_id', 'post');
        $result = $this->_contractPaymentService->deleteContractPayment($paymentId, $dhkId);
        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /**
     * 获取还未完全开完发票的回款记录
     */
    public function actionGetContractPaymentHaveAmountByContract()
    {
        $contractId = $this->getParam('contractId');
        $result = $this->_contractPaymentService->getContractPaymentHaveAmountByContract($contractId);
        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /*发送邮件提醒*/
    /**
     * 应收时间到期前7天提醒
     */
    public function actionReceivableExpiredRemind()
    {
        $this->_contractReceivableService->receivableExpiredRemind();
    }

    /**
     * 根据发票id获取发票信息
     */
    public function actionGetInvoiceInfoById()
    {
        $invoiceId = $this->getParam('invoiceId');
        $result = $this->_invoiceService->getInvoiceInfoById($invoiceId);
        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /**
     * 根据合同业务类型获取不同的应收信息
     */
    public function actionGetPayInfoByContractId()
    {
        $contractId = $this->getParam('contractId', 'get');

        $result = $this->_contractReceivableService->getPayInfoByContractId($contractId);

        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }

    /**
     * 根据合同id获取供应商线下活动支付信息
     */
    public function actionGetSuppliersPaymentByContractId()
    {
        $contractId = $this->getParam('contractId', 'get');
        $result = $this->_contractReceivableService->getSuppliersPaymentByContractId($contractId);

        $this->exportJson($result, $this->_contractPaymentService->getErrCode(), $this->_contractPaymentService->getErrMsg());
    }
}
